home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-05 / pcb121.zip / I8250.INC < prev    next >
Text File  |  1992-01-23  |  17KB  |  443 lines

  1. ;;*****************************************************************************
  2. ;;                         i8250.inc      i8250.inc
  3. ;;*****************************************************************************
  4. ;;
  5. ;;  Copyright (C) 1990 Vance Morrison
  6. ;;
  7. ;;
  8. ;; Permission to view, compile, and modify for LOCAL (intra-organization) 
  9. ;; USE ONLY is hereby granted, provided that this copyright and permission 
  10. ;; notice appear on all copies.  Any other use by permission only.
  11. ;;
  12. ;; Vance Morrison makes no representations about the suitability 
  13. ;; of this software for any purpose.  It is provided "as is" without expressed 
  14. ;; or implied warranty.  See the copywrite notice file for complete details.
  15. ;;
  16. ;;*****************************************************************************
  17. ;; this software essentially is responsible for setup of the 8250 and
  18. ;; getting individual chacters off the serial line.   The routines here
  19. ;; where designed so that they will work with the 16550AF and take advantage
  20. ;; of that chip's read and write FIFOs.
  21. ;;
  22. ;; The functions provided by this file are
  23. ;;
  24. ;;   I8250_DECLARE name, port_prefix, port, io_addr, irq, flow
  25. ;;   I8250_DEFINE_in_BX name, fail
  26. ;;   I8250_WRITE_in_AL_const_BX_BP_ES MACRO name
  27. ;;   I8250_CAN_WRITE_const_BX_CX_BP_SI_DI_ES MACRO name not_ready
  28. ;;
  29. ;;      the following 'upcall' routines will be called from interupt level
  30. ;;  <port_prefix>_CONSUME_in_AL_const_BX_BP_ES 'port' 
  31. ;;  <port_prefix>_WRITE_EMPTY_const_BX_BP_ES 'port' 
  32. ;;
  33. ;;   i8250_&name&_declared                  ;; one if this interface exists
  34. ;;   i8250_declared                         ;; one if ANY interface exists
  35. ;;
  36. ;;******************************************************************************
  37.  
  38.  
  39. ;; 'standard' port numbers
  40. IBM_COM1_PORT = 3F8H
  41. IBM_COM2_PORT = 2F8H
  42. IBM_COM3_PORT = 3E8H
  43. IBM_COM4_PORT = 2E8H
  44.  
  45. ;; and interupts
  46. IBM_COM1_IRQ = 4
  47. IBM_COM2_IRQ = 3
  48.  
  49. ;; the 10 registers of the 8250
  50. I8250_REG_THR = 0       ;; trans hold reg (LCR_DIVISOR = 0) (write only)
  51. I8250_REG_RDR = 0       ;; rec data reg (LCR_DIVISOR = 0) (read only)
  52. I8250_REG_DIVL = 0      ;; baud rate divisor (LCR_DIVISOR = 1)
  53. I8250_REG_DIVH = 1      ;; baud rate divisor (LCR_DIVISOR = 1)
  54. I8250_REG_IER = 1       ;; interupt enable  (LCR_DIVISOR = 0)
  55. I8250_REG_IIR = 2       ;; interupt ident (read only)
  56. NS16550_REG_FIFO = 2    ;; FIFO control register for the NS16550AF chip
  57. I8250_REG_LCR = 3       ;; line control 
  58. I8250_REG_MCR = 4       ;; modem control
  59. I8250_REG_LSR = 5       ;; line status
  60. I8250_REG_MSR = 6       ;; modem status
  61. NS16550_REG_SCR = 7     ;; Scratch register.
  62.  
  63. ;; masks for the IER
  64. I8250_IER_DIN   = 1H        ;; interupt on data in
  65. I8250_IER_DOUT  = 2H        ;; interupt on data ready for out
  66. I8250_IER_ERR   = 4H        ;; interupt on data error
  67. I8250_IER_MODEM = 8H        ;; interupt on modem status change
  68.  
  69. ;; masks for the IIR
  70. I8250_IIR_NOINT   = 1H      ;; the rest of IIR valid only if this bit is 0
  71. I8250_IIR_TYPE    = 6H      ;; type of highest priority interupt
  72. NS16550_IIR_CHECK = 0C0H    ;; Both of these bits must be 1 if its a 16550AF
  73.  
  74. ;; values for type field of the IIR (read only)
  75. I8250_TYPE_MODEM  = 0H      ;; notice they are shifted to the TYPE field
  76. I8250_TYPE_DOUT   = 2H 
  77. I8250_TYPE_DIN    = 4H 
  78. I8250_TYPE_ERR    = 6H 
  79.  
  80. ;; masks for the FIFO reg   (write only)
  81. NS16550_FIFO_ON   = 1       ;; Enable the FIFOs
  82. NS16550_FIFO_FIN  = 2       ;; Flush input FIFO
  83. NS16550_FIFO_FOUT = 4       ;; Flush input FIFO
  84. NS16550_FIFO_TRIG = 0C0H    ;; bytes in input FIFO before interupt
  85.  
  86. ;; values for the TRIG field of the FIFO reg
  87. NS16550_TRIG_1    = 000H    ;; trigger on 1 byte 
  88. NS16550_TRIG_4    = 040H    ;; trigger on 4 bytes
  89. NS16550_TRIG_8    = 080H    ;; trigger on 8 bytes
  90. NS16550_TRIG_14   = 0C0H    ;; trigger on 14 bytes
  91.  
  92. ;; masks for the LCR
  93. I8250_LCR_BITS    = 3H      ;; number of bits - 5
  94. I8250_LCR_STOP    = 4H
  95. I8250_LCR_PARITY  = 38H
  96. I8250_LCR_BREAK   = 40H     ;; send a break
  97. I8250_LCR_DIVISOR = 80H     ;; make reg 0,1 be the divisor register
  98.  
  99. ;; values for the parity field of the LCR
  100. I8250_PARITY_IGN   = 0H     ;; notice they are shifted
  101. I8250_PARITY_ODD   = 20H
  102. I8250_PARITY_EVEN  = 30H
  103. I8250_PARITY_MARK  = 28H
  104. I8250_PARITY_SPACE = 38H
  105.  
  106. ;; masks for the MCR
  107. I8250_MCR_DTR     = 1H      ;; activate DTR line
  108. I8250_MCR_RTS     = 2H      ;; activate RTS line
  109. I8250_MCR_OUT1    = 4H      ;; out1 Line
  110. I8250_MCR_OUT2    = 8H      ;; out2 line
  111. I8250_MCR_LOOP    = 10H     ;; loopback
  112.  
  113. ;; masks for the LSR
  114. I8250_LSR_DIN     = 1H      ;; data in read register
  115. I8250_LSR_OVR     = 2H      ;; data overun
  116. I8250_LSR_PERR    = 4H      ;; data parity error
  117. I8250_LSR_FERR    = 8H      ;; data framing error
  118. I8250_LSR_BREAK   = 10H     ;; break detected
  119. I8250_LSR_DOUT    = 20H     ;; Transmit buffer empty
  120. I8250_LSR_TSR     = 40H     ;; Transmit shift reg empty (no data on line)
  121.  
  122. ;; masks for the MSR
  123. I8250_MSR_DELTA_CTS   = 1H  ;; CTS changed
  124. I8250_MSR_DELTA_DSR   = 2H  ;; DSR changed
  125. I8250_MSR_DELTA_RI    = 4H  ;; RI changed
  126. I8250_MSR_DELTA_DCD   = 8H  ;; DCD changed
  127. I8250_MSR_CTS         = 10H ;; CTS active
  128. I8250_MSR_DSR         = 20H ;; DSR active
  129. I8250_MSR_RI          = 40H ;; RI active
  130. I8250_MSR_DCD         = 80H ;; DCD active
  131.  
  132. ;;*****************************************************************************
  133. ;; defs for the I8259 programable interupt controller
  134.  
  135. IBM_I8259    = 20H          ;; standard place on the IBM PC
  136.  
  137. I8259_REG_CNTRL       = 0   ;; the 8259 control register
  138. I8259_REG_MASKS       = 1   ;; the interupt mask register
  139.  
  140. ;; control register functions
  141. I8259_CNTRL_EOI       = 20H ;; the End of Interupt command
  142.  
  143.  
  144. ;;*****************************************************************************
  145. ;;   I8250_DECLARE declares your intent to use a 8250 serial controler at 
  146. ;;   address 'io_addr', using interupt 'irq'.  When it gets characters it calls
  147. ;;  <port_prefix>_CONSUME_in_AL_const_BX_BP_ES 'port' and 
  148. ;;  <port_prefix>_WRITE_EMPTY_const_BX_CX_DX_BP_SI_DI_ES 'port' when it 
  149. ;;  can write characters.  If 'flow' is non-blank and = 1
  150. ;;  then hardware flow control using RTS-CTS is followed.  
  151. ;;
  152. I8250_DECLARE MACRO name, port_prefix, port, io_addr, irq, flow
  153.     .errb <name>
  154.     .errb <irq>
  155.  
  156.     .DATA
  157.     i8250_declared            = name
  158.     i8250_&name&_port         = port
  159.     i8250_&name&_prefix       equ <port_prefix>
  160.     i8250_&name&_declared     = 1
  161.     i8250_&name&_io           = io_addr
  162.     i8250_&name&_irq          = irq
  163.  
  164.     i8250_&name&_flow         = 0
  165.     ifnb <flow>
  166.         i8250_&name&_flow     = 0&flow
  167.     endif
  168.  
  169.     .CODE
  170.     global i8250_data_seg:word
  171.     global i8250_&name&_real_define_in_BX_out_AX:near
  172. ENDM
  173.  
  174.  
  175. ;;******************************************************************************
  176. ;;   I8250_DEFINE name, fail
  177. ;;      sets asside memory an name object and initializes it.  This
  178. ;;      routine is a no-op if 'name' was not declared.  It jumps to 'fail'
  179. ;;      if there was an error in  setup.  BX contains the word that
  180. ;;      is the baud rate divisor.  (12 = 9600Baud, 6 = 19200Baud, etc)
  181. ;;
  182. I8250_DEFINE_in_BX MACRO name, fail
  183.    .errb <name>
  184.    .errb <fail>
  185.  
  186. ifdef i8250_&name&_declared
  187.     call i8250_&name&_real_define_in_BX_out_AX
  188.     or AX, AX
  189.     jnz fail
  190. endif
  191. ENDM
  192.  
  193. ;;*************************************************************************
  194. ;; I8250_REAL_DEFINE is simply a the code that I8250_DEFINE jumps to.
  195. ;; this indirection is necessary to avoid macros getting too large.
  196. ;;
  197. I8250_REAL_DEFINE MACRO name
  198.     local done
  199.     .errb <name>
  200.  
  201. ifdef i8250_&name&_declared
  202.     i8250_&name&_real_define_in_BX_out_AX:
  203.  
  204.     mov word ptr CS:i8250_data_seg, DS      ;; make sure interupt routine OK
  205.  
  206.         ;; turn off my interupt
  207.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8259_REG_MASKS, IBM_I8259  
  208.     and AL, (1 shl i8250_&name&_irq)
  209.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES I8259_REG_MASKS, IBM_I8259   
  210.  
  211.     I8250_SETUP_in_BX_out_AX name, done
  212.  
  213.         ;; turn on my interupt
  214.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8259_REG_MASKS, IBM_I8259  
  215.     and AL, (not (1 shl i8250_&name&_irq))
  216.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES I8259_REG_MASKS, IBM_I8259   
  217.     sti             ;; turn on interupts, if not already on
  218.  
  219.     xor AX, AX                          ;; return success
  220.     done:
  221.     ret
  222.  
  223. if i8250_declared eq name           ; define once for all
  224.  
  225.     ;;*****************************************************************
  226.     ;; define the interupt handler
  227.     .CODE
  228.     i8250_data_seg: DW 0        ;; this location hold the data segment
  229.  
  230.     i8250_interupt:             ;; the actual interupt handler
  231.     cli
  232.     push DS
  233.     push AX
  234.     push CX
  235.     push DX
  236.     push SI
  237.     push DI
  238.     mov DS, word ptr CS:i8250_data_seg
  239.  
  240.     IRP idx, <1,2,3,4,5,6,7,8>      ;; check every chip
  241.        I8250_IF_CHECK_const_BX_BP_ES idx
  242.     endm
  243.  
  244.     mov AL, I8259_CNTRL_EOI             ; tell the 8259 we are done
  245.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES I8259_REG_CNTRL, IBM_I8259   
  246.     pop DI
  247.     pop SI
  248.     pop DX
  249.     pop CX
  250.     pop AX
  251.     pop DS
  252.     iret                                ; interupts flag restored on return
  253. endif
  254. endif
  255.  
  256. ENDM
  257.  
  258.  
  259. ;;******************************************************************************
  260. ;; I8250_SETUP does all the 'per chip' setup for a 8250 serial chip associated
  261. ;; with 'name'.  if there is a failure 'fail' is jumped to, AX will have a
  262. ;; non-zero value if the 'fail' branch is taken.  BX contains the word that
  263. ;; is the baud rate divisor.  (12 = 9600Baud, 6 = 19200Baud)
  264. ;;
  265. I8250_SETUP_in_BX_out_AX MACRO name, fail
  266.     local done, is_a_16550AF, is_a_8250
  267.  
  268. ifdef i8250_&name&_declared
  269.         ; check to see that a serial port is there by reading 8250 register
  270.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_LSR, i8250_&name&_io
  271.     cmp AL, 0FFH                ;; non-existant registers turn up as all 1s
  272.     jz fail
  273.  
  274.         ;; set the baud rate divisor 
  275.     mov AL, I8250_LCR_DIVISOR 
  276.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES I8250_REG_LCR,i8250_&name&_io
  277.  
  278.     mov AX, BX                  ;; get the baud rate
  279.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES I8250_REG_DIVL, i8250_&name&_io
  280.     mov AL, AH
  281.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES I8250_REG_DIVH,i8250_&name&_io
  282.  
  283.     mov AL, (8-5) + I8250_PARITY_IGN        ;; 8 bits no parity 1 stop bit
  284.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES I8250_REG_LCR, i8250_&name&_io
  285.  
  286.     if i8250_&name&_flow eq 1
  287.         mov AL, I8250_IER_DIN + I8250_IER_DOUT + I8250_IER_MODEM
  288.     else
  289.         mov AL, I8250_IER_DIN + I8250_IER_DOUT
  290.     endif
  291.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES I8250_REG_IER, i8250_&name&_io
  292.  
  293.         ;; Turn on FIFO mode if this is a 16550AF
  294.     mov AL, NS16550_FIFO_ON+NS16550_FIFO_FIN+NS16550_FIFO_FOUT+NS16550_TRIG_8
  295.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES NS16550_REG_FIFO,i8250_&name&_io
  296.  
  297.         ;; make sure that this is a 16550AF not just a 16550 (which has a bug)
  298.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_IIR, i8250_&name&_io
  299.     and AL, NS16550_IIR_CHECK
  300.     test AL, 80H                    ;; is it a 16550?
  301.     jz is_a_8250
  302.     test AL, 40H                    ;; is it a 16550AF?
  303.     jnz is_a_16550AF
  304.         mov AL, 0                   ;; turn off FIFO, the 16550 is buggy
  305.         WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES NS16550_REG_FIFO,i8250_&name&_io
  306.     is_a_16550AF:
  307.     is_a_8250:
  308.  
  309.         ;; set DTR and RTS for those modems that care
  310.         ;; ON AN IBM PC OUT2 MUST BE SET FOR PROPER OPERATION
  311.     mov AL, I8250_MCR_DTR + I8250_MCR_RTS + I8250_MCR_OUT2
  312.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES I8250_REG_MCR, i8250_&name&_io
  313.  
  314.     cli
  315.     xor AX, AX                  ;; load the interupt vector
  316.     mov ES, AX
  317.     mov DI, (i8250_&name&_irq+8)*4 
  318.     mov BX, offset i8250_interupt
  319.     mov AX, CS
  320.     mov ES:[DI], BX
  321.     mov ES:[DI+2], AX
  322.     sti
  323.  
  324.         ; acknowledge any interupts that may have occured in the past
  325.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_RDR, i8250_&name&_io
  326.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_MSR, i8250_&name&_io
  327.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_IIR, i8250_&name&_io
  328. endif
  329. ENDM
  330.  
  331.  
  332. ;;******************************************************************************
  333. ;; I8250_IF_CHECK checks to see of interface 'name' has any characters to write
  334. ;; or to read and does the appropriate upcall if there is anthing to do.
  335. ;;
  336. I8250_IF_CHECK_const_BX_BP_ES MACRO name
  337.     local done, try_write, try_read, done_write
  338.  
  339. ifdef i8250_&name&_declared  
  340.     try_read:
  341.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_LSR, i8250_&name&_io
  342.     and AL, I8250_LSR_DIN               ;; is there a character ready?
  343.     jz try_write
  344.  
  345.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_RDR, i8250_&name&_io
  346.     UPCALL_CONSUME_in_AL_const_BX_BP_ES %i8250_&name&_prefix, %i8250_&name&_port
  347.     jmp try_read                        ;; keep trying until failure (for 16650)
  348.  
  349.     try_write:
  350.         ; acknowledge the Tran Empty interupt
  351.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_IIR, i8250_&name&_io
  352.  
  353.     I8250_CAN_WRITE_const_BX_CX_BP_SI_DI_ES name, done_write
  354.        UPCALL_WRITE_EMPTY_const_BX_BP_ES %i8250_&name&_prefix,%i8250_&name&_port
  355.     done_write:
  356.  
  357.         ;; have all the interupts been processed?
  358.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_IIR, i8250_&name&_io
  359.     test AL, I8250_IIR_NOINT
  360.     jz try_read                 ;; no, then try again until they are
  361.  
  362.         ;; Note that this final check for interupts is absolutely 
  363.         ;; necessary because the 8259 responds to EDGES, not LEVELs
  364.         ;; only if we are absolutely sure the interupt line has gone
  365.         ;; low (which would be the case if IIR has NOINT bit = 1) can
  366.         ;; we be sure that the next interupt will generate an EDGE
  367.         ;; the the 8259 will respond to.   Without this check it is 
  368.     ;; possible for interupts from the 8250 to be lost causing 
  369.     ;; the code to hang
  370.     done:
  371. endif
  372. ENDM
  373.  
  374. UPCALL_CONSUME_in_AL_const_BX_BP_ES MACRO prefix, port
  375.     prefix&_CONSUME_in_AL_const_BX_BP_ES port 
  376. ENDM
  377.     
  378. UPCALL_WRITE_EMPTY_const_BX_BP_ES MACRO prefix, port
  379.     prefix&_WRITE_EMPTY_const_BX_BP_ES port
  380. ENDM
  381.  
  382.  
  383. ;;******************************************************************************
  384. ;; W_CAN_WRITE jumps to 'not_ready' if the 8250 chip associated with
  385. ;; 'name' is not ready to recieve another byte.  Otherwise it just returns.
  386. ;;
  387. I8250_CAN_WRITE_const_BX_CX_BP_SI_DI_ES MACRO name, not_ready
  388.     .errb <name>
  389.     .errb <success>
  390.  
  391.         ;; if we are doing flow control, we can only send if CTS is active
  392.     if i8250_&name&_flow eq 1
  393.         READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_MSR, i8250_&name&_io
  394.         and AL, I8250_MSR_CTS
  395.         jz not_ready
  396.     endif
  397.  
  398.     READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_LSR, i8250_&name&_io
  399.     and AL, I8250_LSR_DOUT              ;; is there a character ready?
  400.     jz not_ready
  401. ENDM
  402.     
  403.  
  404. ;;******************************************************************************
  405. ;; WRITE_in_AL writes the character in AL to the chip 'name'.  It
  406. ;; will busy wait if necessary, however this routine is guarenteed not
  407. ;; to busy wait if it is called only when the WRITE_EMPTY upcall is issued.
  408. ;;
  409. I8250_WRITE_in_AL_const_BX_BP_ES MACRO name
  410.     local wait_loop, ready
  411.     .errb <name>
  412.  
  413.     mov SI, AX                              ;; save AL
  414.     xor CX, CX
  415.     wait_loop:
  416.         READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES I8250_REG_LSR, i8250_&name&_io
  417.         and AL, I8250_LSR_DOUT              ;; is there a character ready?
  418.         jnz ready
  419.         dec CX                              ;; so we don't wait forever
  420.         jnz wait_loop
  421.  
  422.     ready:
  423.     mov AX, SI                              ;; restore AL
  424.     WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES I8250_REG_THR, i8250_&name&_io
  425.  
  426. ENDM
  427.  
  428.  
  429. ;;******************************************************************************
  430. ;; utility functions needed only within this module
  431.  
  432. READ_PORT_out_AL_const_BX_CX_BP_SI_DI_ES MACRO port, if_io
  433.     mov DX, if_io+port
  434.     in  AL, DX                              ;; AL contains data read from port
  435. ENDM
  436.  
  437. ;;******************************************************************************
  438. WRITE_PORT_in_AL_const_AX_BX_CX_BP_SI_DI_ES MACRO port, if_io
  439.     mov DX, if_io+port
  440.     out DX, AL                              ;; AL contains data read from port
  441. ENDM 
  442.  
  443.